﻿#region Librerias

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using ESF.General;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;

#endregion


namespace ESF.FileProcessing
{
	public static class TIFFHelper
	{
		public static int GetItemCount (string pFileName)
		{
			Stream imageStreamSource; 

			TiffBitmapDecoder decoder;


			if (Path.GetExtension (pFileName).ToUpper () == ".TIF")
			{
				using (imageStreamSource = FileHelper.GetFileStream(pFileName))
				{
					decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

					return decoder.Frames.Count;
				}
			}

			return 1;
		}


		#region Create

		public static void CreateTIFF (string pTIFFFileName, params string [] pImageFileNames)
		{
			FileHelper.Delete (pTIFFFileName);

			FileHelper.EnsureFolder (pTIFFFileName);


			using (FileStream stream = new FileStream (pTIFFFileName, FileMode.Create))
			{            
				TiffBitmapEncoder encoder = new TiffBitmapEncoder();
            
				encoder.Compression = TiffCompressOption.Zip;
            
				foreach (string pFileItem in pImageFileNames)
				{
					encoder.Frames.Add (BitmapFrame.Create (FileHelper.GetFileStream (pFileItem)));				
				}

				encoder.Save (stream);
			}
		}

		#endregion


		#region Merge

		public static void MergeTIFFImages (string pMergedFileName, params string [] pSortedTIFFFilenames)
		{
			List<string> pImagesExtracted = new List<string> ();


			if (DataHelper.IsEmpty (pSortedTIFFFilenames))
			{
				throw new ArgumentException ("Is not specified a list of sorted filenames");
			}

			if (pSortedTIFFFilenames.Length == 1) 
			{ 
				File.Copy (pSortedTIFFFilenames [0], pMergedFileName);

				return; 
			}

			foreach (string pFileItem in pSortedTIFFFilenames)
			{			
				pImagesExtracted.AddRange (ExtractImages (pFileItem));
			}

			CreateTIFF (pMergedFileName, pImagesExtracted.ToArray ());
		}

		#endregion


		#region Extraction

		public static void DeleteExtractedImages(string pFileName)
		{
			DeleteExtractedImages (pFileName, ReadConfig.TempDirectory);
		}


		public static void DeleteExtractedImages(string pFileName, string pExtractDirectory)
		{
			FileHelper.DeleteDirectory (Path.Combine(pExtractDirectory, "ExtractImages", TextHelper.GetMD5Hash(pFileName)));
		} 


		public static string [] ExtractImages (string pFileName)
		{
			return ExtractImages (pFileName, ReadConfig.TempDirectory);
		}


		public static string [] ExtractImages (string pFileName, string pExtractDirectory)
		{
			int? imageCount;
			int currentLengthPadLeft;

			string [] imageList;

			
			try
			{
				pExtractDirectory = Path.Combine(pExtractDirectory, "ExtractImages", TextHelper.GetMD5Hash(pFileName));

				imageList = FileHelper.ListFiles(pExtractDirectory, pFileExtensions: new string[] { ".png", ".jpg", ".bmp", ".gif" }, pSearchOption: SearchOption.TopDirectoryOnly).ToArray();
				
				imageCount = ProcessFileHelper.GetItemCount(pFileName);
				
				if (imageCount == null)
				{
					throw new NotSupportedException (string.Format ("Read file {0} is not supported", pFileName));
				}

				// Si la carpeta ya fue procesada existe y se omite la extraccion
				// si no existe se extraen las imagenes
				if (imageList.Length != imageCount)
				{
					DeleteExtractedImages (pFileName);

					FileHelper.EnsureFolder(pExtractDirectory);
				
					currentLengthPadLeft = imageCount.ToString ().Length;

					if (imageCount == 1 && Path.GetExtension (pFileName).ToUpper () != ".TIF")
					{
						FileHelper.Copy (pFileName, Path.Combine(pExtractDirectory, "1" + Path.GetExtension (pFileName)));
					}
					else
					{	
						Parallel.For (0, imageCount.Value, ProcessHelper.DefaultParallelOptions,
						(int pImageIndex) =>
						{
							using (Stream imageStreamSource = FileHelper.GetFileStream (pFileName))
							{
								string tmpFileNameX;
							
								BitmapDecoder decoder = BitmapDecoder.Create (imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

							
								#region Extension

								string extension;

								BitmapEncoder encoder;


								if (decoder is TiffBitmapDecoder || decoder is PngBitmapDecoder)
								{
									encoder = new PngBitmapEncoder ();
									extension = ".png";
								}
								else if (decoder is BmpBitmapDecoder)
								{
									extension = ".bmp"; 
									encoder = new BmpBitmapEncoder();
								}
								else if (decoder is GifBitmapDecoder)
								{
									extension = ".gif"; 
									encoder = new GifBitmapEncoder();
								}
								else
								{
									extension = ".jpg"; 
									encoder = new JpegBitmapEncoder();
								}

								#endregion

								encoder.Frames.Add (decoder.Frames [pImageIndex]);
									
								tmpFileNameX = Path.Combine(pExtractDirectory, pImageIndex.ToString ().PadLeft (currentLengthPadLeft, '0') + extension);

								FileHelper.Delete (tmpFileNameX);

								using (FileStream file = new FileStream (tmpFileNameX, FileMode.Create))
								{
									encoder.Save(file);
								}

								GC.Collect();
							}
						});
					}

					imageList = FileHelper.ListFiles(pExtractDirectory, pFileExtensions: new string[] { ".png", ".jpg", ".bmp", ".gif" }, pSearchOption: SearchOption.TopDirectoryOnly).ToArray();
				}				
				
				if (imageList.Length == 0)
				{
					throw new Exception(string.Format("Empty result for Extraction of images for {0}", pFileName));
				}

				return imageList;
			}
			catch (Exception pEx)
			{
				Log.WriteLog ("ImageError", string.Format ("Error in the Extraction of images for:\n{0}\nDetail:\n{1}", pFileName, GenericException.ToString (pEx)));
				
				throw new Exception (string.Format ("Error in the Extraction of images for {0}", pFileName), pEx);
			}
		}

		#endregion
	}
}
